package ru.braim.weather_app.services;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import ru.braim.weather_app.dto.account.AccountRequestDTO;
import ru.braim.weather_app.dto.account.AccountResponseDTO;
import ru.braim.weather_app.models.Account;
import ru.braim.weather_app.repositories.AccountRepository;
import ru.braim.weather_app.responses.account.AccountResponse;
import ru.braim.weather_app.responses.account.AccountsResponse;
import ru.braim.weather_app.utils.password_hashes.PasswordHashes;
import ru.braim.weather_app.utils.validators.models.AccountValidator;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

@Service
public class AccountService {

    private final AccountRepository accountRepository;

    public AccountService(AccountRepository accountRepository) {
        this.accountRepository = accountRepository;
    }

    public AccountResponse createAccount(AccountRequestDTO accountRequestDTO, String cookie) {

        Account account = AccountValidator.getValidAccount(accountRequestDTO);

        if (account == null) {
            return new AccountResponse(null, HttpStatus.BAD_REQUEST);
        }


        byte[] salt = PasswordHashes.createSalt();
        byte[] hashedPassword = PasswordHashes.hashPassword(account.getPassword(), salt);

        if (
                !account.setPassword(PasswordHashes.encodeToString(hashedPassword)) ||
                !account.setSalt(PasswordHashes.encodeToString(salt))){
            return new AccountResponse(null, HttpStatus.BAD_REQUEST);
        }

        if (!account.setCookie(cookie)) {
            return new AccountResponse(null, HttpStatus.BAD_REQUEST);
        }


        if (accountRepository.existsByEmail(accountRequestDTO.getEmail())) {
            return new AccountResponse(null, HttpStatus.CONFLICT);
        }


        account = accountRepository.save(account);
        accountRequestDTO.setId(account.getId());


        AccountResponseDTO accountResponseDTO = new AccountResponseDTO();
        accountResponseDTO.convertAccountRequestDTOToAccountResponseDTO(accountRequestDTO);

        return new AccountResponse(accountResponseDTO, HttpStatus.CREATED);

    }

    public AccountResponse authInAccount(AccountRequestDTO accountRequestDTO) {

        if (!accountRepository.existsByEmail(accountRequestDTO.getEmail())) {
            return new AccountResponse(null, HttpStatus.UNAUTHORIZED);
        }

        Optional<Account> accountOptional = accountRepository.findByEmail(accountRequestDTO.getEmail());

        if (accountOptional.isPresent()) {
            Account account = accountOptional.get();


            String salt = account.getSalt();
            String password = account.getPassword();

            String request_password = PasswordHashes.encodeToString(
                    PasswordHashes.hashPassword(accountRequestDTO.getPassword(), PasswordHashes.encodeToByte(salt)));

            if (request_password.equals(password)) {
                AccountResponseDTO accountResponseDTO = new AccountResponseDTO();
                accountResponseDTO.setId(account.getId());
                return new AccountResponse(accountResponseDTO, HttpStatus.OK);
            }

        }

        return new AccountResponse(null, HttpStatus.UNAUTHORIZED);


    }

    public boolean updateCookieInAccount(AccountResponseDTO accountResponseDTO, String cookie) {
        Account account = accountRepository.findById(accountResponseDTO.getId()).orElse(null);
        if (account == null) {
            return false;
        }
        account.setCookie(cookie);
        accountRepository.save(account);
        return true;
    }

    public boolean checkCookieInAccount(String cookie) {
        return accountRepository.existsAccountByCookie(cookie);
    }

    public AccountResponse getAccountById(int id) {

        if (id <= 0) {
            return new AccountResponse(null, HttpStatus.BAD_REQUEST);
        }

        Optional<Account> accountOptional = accountRepository.findById(id);
        if (accountOptional.isPresent()) {
            Account account = accountOptional.get();
            AccountResponseDTO accountResponseDTO = new AccountResponseDTO();

            accountResponseDTO.setId(account.getId());
            accountResponseDTO.setEmail(account.getEmail());
            accountResponseDTO.setFirstName(account.getFirstName());
            accountResponseDTO.setLastName(account.getLastName());

            return new AccountResponse(accountResponseDTO, HttpStatus.OK);
        }
        return new AccountResponse(null, HttpStatus.NOT_FOUND);

    }
    
    public AccountsResponse getAccountsBySearch(String firstName, String lastName, String email, int form, int size) {

        if (form < 0 || size <= 0) {
            return new AccountsResponse(null, HttpStatus.BAD_REQUEST);
        }

        Pageable pageable = PageRequest.of(form, size, Sort.by("id").ascending());


        Page<Account> accounts = accountRepository
                .getAccountByFirstNameContainingIgnoreCaseAndLastNameContainingIgnoreCaseAndEmailContainingIgnoreCase
                        (firstName, lastName, email, pageable);


        AccountsResponse accountsResponse = new AccountsResponse();
        List<AccountResponseDTO> accountsResponseDTOList = new ArrayList<>();

        for (Account account : accounts.getContent()) {
            AccountResponseDTO accountResponseDTO = new AccountResponseDTO();
            accountResponseDTO.convertAccountToAccountResponseDTO(account);
            accountsResponseDTOList.add(accountResponseDTO);
        }

        accountsResponse.setAccountsResponseDTO(accountsResponseDTOList);


        return new AccountsResponse(accountsResponseDTOList, HttpStatus.OK);

    }



    public AccountResponse updateAccount(int id, AccountRequestDTO accountRequestDTO, String cookie) {

        if (id <= 0) {
            return new AccountResponse(null, HttpStatus.BAD_REQUEST);
        }

        Account account = AccountValidator.getValidAccount(accountRequestDTO);

        if (account == null) {
            return new AccountResponse(null, HttpStatus.BAD_REQUEST);
        }

        Optional<Account> accountOptional = accountRepository.findById(id);

        if (accountOptional.isEmpty()) {
            return new AccountResponse(null, HttpStatus.FORBIDDEN);
        }


        Account accountFromRepository = accountOptional.get();

        if (!accountFromRepository.getCookie().equals(cookie)) {
            return new AccountResponse(null, HttpStatus.FORBIDDEN);
        }

        String salt = accountFromRepository.getSalt();
        String password = accountFromRepository.getPassword();

        String request_password = PasswordHashes.encodeToString(
                PasswordHashes.hashPassword(accountRequestDTO.getPassword(), PasswordHashes.encodeToByte(salt)));

        if (!request_password.equals(password)) {
            return new AccountResponse(null, HttpStatus.FORBIDDEN);
        }

        AccountResponseDTO accountResponseDTO = new AccountResponseDTO();

        accountFromRepository.setFirstName(account.getFirstName());
        accountFromRepository.setLastName(account.getLastName());
        accountFromRepository.setEmail(account.getEmail());

        if (accountRepository.existsByEmail(accountFromRepository.getEmail())) {
            return new AccountResponse(null, HttpStatus.CONFLICT);
        }

        accountRepository.save(accountFromRepository);

        accountResponseDTO.convertAccountToAccountResponseDTO(accountFromRepository);

        return new AccountResponse(accountResponseDTO, HttpStatus.OK);

    }


    public AccountResponse deleteAccount(int id, String cookie) {

        if (id <= 0) {
            return new AccountResponse(null, HttpStatus.BAD_REQUEST);
        }

        Optional<Account> accountOptional = accountRepository.findById(id);

        if (accountOptional.isEmpty()) {
            return new AccountResponse(null, HttpStatus.FORBIDDEN);
        }

        Account accountFromRepository = accountOptional.get();

        if (!accountFromRepository.getCookie().equals(cookie)) {
            return new AccountResponse(null, HttpStatus.FORBIDDEN);
        }

        accountRepository.deleteById(accountFromRepository.getId());

        return new AccountResponse(null, HttpStatus.OK);

    }


}
